namespace Gsl
{
    using System;
    using System.Collections;
    using System.IO;
    using System.Runtime.InteropServices;
    
    [StructLayout(LayoutKind.Sequential)]
    public class Vector : ICloneable, IEnumerable
    {
        int size;
        int stride;
        double[] data;
        Block block;
        int owner;
        
        public Vector(int size)
        {
            block = new Block(size);
            
            data = block.Data;
            this.size = size;
            stride = 1;
            owner = 1;
        }
        
        public int Size
        {
            get { return size; }
        }
        
        //
        // Accessing vector elements
        //
        
        public double this [int i]
        {
            get { return data[i]; }
            set { data[i] = value; }
        }
        
        public double[] Data
        {
            get { return data; }
        }
        
        //
        // Initializing vector elements
        //
                        
        public void SetAll(double x)
        {
            //gsl_vector_set_all(this, x);
            for (int i = 0; i < size; i++)
                data[i] = x;
        }
        
        public void SetZero()
        {
            //gsl_vector_set_zero(this);
            for (int i = 0; i < size; i++)
                data[i] = 0.0;
        }
        
        public void SetBasis(int index)
        {
            //gsl_vector_set_basis(this, i);
            for (int i = 0; i < size; i++)
                data[i] = 0.0;
            data[index] = 1.0;
        }
        
        //
        // Reading and writing vectors
        //
        
        public void Write(Stream stream)
        {
            BinaryWriter writer = new BinaryWriter(stream);
            for (int i = 0; i < size; i++)
                writer.Write(this[i]);
            writer.Close();
        }
        
        public void Read(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);
            for (int i = 0; i < size; i++)
                this[i] = reader.ReadDouble();
            reader.Close();
        }
        
        public void Print(Stream stream, string format)
        {
            StreamWriter writer = new StreamWriter(stream);
            for (int i = 0; i < size; i++)
                writer.WriteLine(format, this[i]);
            writer.Close();
        }
        
        public void Scan(Stream stream)
        {
            StreamReader reader = new StreamReader(stream);
            for (int i = 0; i < size; i++)
                this[i] = Double.Parse(reader.ReadLine());
            reader.Close();
        }
        
        //
        // skip vector view stuff -- looks uselesss to me ...
        //
        
        //
        //  I doubt I'll use any of the following, so whatever.
        //
        
        //
        // Copying vectors
        //
        
        [DllImport("libgsl")] private static extern int gsl_vector_memcpy(Vector dest, Vector src);
        [DllImport("libgsl")] private static extern int gsl_vector_swap(Vector v, Vector w);
        
        public static void Swap(ref Vector v1, ref Vector v2)
        {
            if (v1.Size != v2.Size)
                throw new GslException("Vector.Swap: vector length not equal", Error.Code.GSL_EBADLEN);
                
            Error.Code ret = (Error.Code)gsl_vector_swap(v1, v2);
            if (ret != Error.Code.GSL_SUCCESS)
                throw new GslException("Vector.Swap error", ret);
        }
        
        public static void Copy(ref Vector dest, Vector src)
        {
            if (dest.Size != src.Size)
                throw new GslException("Vector.Copy: vector length not equal", Error.Code.GSL_EBADLEN);
            
            Error.Code ret = (Error.Code)gsl_vector_memcpy(dest, src);
            if (ret != Error.Code.GSL_SUCCESS)
                throw new GslException("Vector.Copy error", ret);
        }
                             
        public object Clone()
        {
            Vector v = new Vector(size);
            for (int i = 0; i < size; i++)
                v[i] = this[i];
                
            return v;
        }
        
        //
        // Exchanging elements
        //              
        
        [DllImport("libgsl")] private static extern int gsl_vector_swap_elements(Vector v, int i, int j);
        [DllImport("libgsl")] private static extern int gsl_vector_reverse(Vector v);
        
        public void SwapElements(int i, int j)
        {
            Error.Code ret = (Error.Code)gsl_vector_swap_elements(this, i, j);
            if (ret != Error.Code.GSL_SUCCESS)
                throw new GslException("Vector.SwapElements error", ret);
        }
        
        public void Reverse()
        {
            Error.Code ret = (Error.Code)gsl_vector_reverse(this);
            if (ret != Error.Code.GSL_SUCCESS)
                throw new GslException("Vector.Reverse error", ret);
        }
        
        //
        // Vector operations
        //
                                                                    
        public IEnumerator GetEnumerator()
        {
            return new VectorEnumerator(this);
        }
        
        public class VectorEnumerator : IEnumerator
        {
            private int index;
            private Vector vector;

            public VectorEnumerator(Vector v)
            {
                index = -1;
                vector = v;
            }

            public void Reset()
            {
                index = -1;
            }
            
            public object Current
            {
                get
                {
                    if (index > -1)
                        return vector[index];
                    else
                        return -1;
                }
            }

            public bool MoveNext()
            {
                index++;
                if (index < vector.Size)
                    return true;
                else
                    return false;
            }
        }
    }
}        
        
        
